<?php
declare (strict_types=1);

namespace app\admin\controller\dev;

use app\admin\annotation\common\Auth;
use app\admin\controller\Admin;
use app\admin\model\admin\I18n as I18nModel;
use app\admin\model\dev\Menu as MenuModel;
use app\admin\model\dev\Field as FieldModel;
use app\admin\service\common\SortableService;
use app\admin\service\dev\DatabaseService;
use app\admin\validate\dev\Menu as MenuValidate;
use app\admin\service\dev\MenuService;
use app\common\Constants;
use app\common\exception\BusinessException;
use app\common\facade\StrHelper;
use think\facade\Config;
use think\facade\Db;
use think\facade\Log;

class Menu extends Admin
{

    /**
     * 菜单列表
     * @return \think\response\Json
     */
    #[Auth('dev:menu:index')]
    public function index(): \think\response\Json
    {
        $param = $this->request->post();
        try {
            validate(MenuValidate::class)
                ->scene('index')
                ->check($param);

            $query = MenuModel::withPerms();

            $query->when(isset($param['role_id']), function ($query) use ($param) {
                $keyword = str_replace(['%', '_'], ['\%', '\_'], $param['keyword']);
                $query->where('name|controller|remark', 'like', "%" . $keyword . "%");
            });

            $orderBy = sort_rules($param['order_by'] ?? 'sort|desc');
            $query->order($orderBy);

            $list['data'] = $query->select()->toArray();
            $list['sort'] = $orderBy;

            return $this->success(['data' => $list]);
        } catch (\think\Exception\ValidateException $ve) {
            return $this->error(['message' => $ve->getMessage()]);
        } catch (\Exception $e) {
            throw $e;
        }
    }


    /**
     * 添加菜单数据
     *
     * @return \think\response\Json
     */
    #[Auth('dev:menu:add')]
    public function add(): \think\response\Json
    {
        try {
            $post = $this->request->post();
            validate(MenuValidate::class)->scene('add')->check($post);
            $menu_id = MenuService::addMenu($post);
            return $this->success(['data' => $menu_id]);
        } catch (\think\Exception\ValidateException $ve) {
            return $this->error(['message' => $ve->getMessage()]);
        } catch (\Exception $e) {
            throw $e;
        }
    }


    /**
     * 更新菜单数据
     * @return \think\response\Json
     */
    #[Auth('dev:menu:update')]
    public function update()
    {
        try {
            $post = $this->request->post();
            validate(MenuValidate::class)->scene('update')->check($post);
            MenuService::updateMenu($post);
            return $this->success();
        } catch (\think\Exception\ValidateException $ve) {
            return $this->error(['message' => $ve->getMessage()]);
        } catch (\Exception $e) {
            throw $e;
        }
    }


    /**
     * 用于更新的数据
     * @return \think\response\Json
     */
    #[Auth('dev:menu:update')]
    public function getFormData(): \think\response\Json
    {

        $id = $this->request->param('id');
        if (!$id) {
            return $this->error(['message' => Constants::E_COMMON_INVALID_PARAM]);
        }
        $result = MenuModel::find($id)->toArray();
        if (!$result) {
            return $this->error(['message' => Constants::E_COMMON_RECORD_NOT_FOUND]);
        }
        // 根据多语言key获取多语言翻译数据
        if ($result['key']) {
            $result['translations'] = I18nModel::where('key', $result['key'])->column('value', 'lang_code');
        }
        return $this->success(['data' => $result]);

    }


    /**
     * 获得菜单详情数据
     * @return \think\response\Json
     */
    #[Auth('dev:menu:detail')]
    public function detail(): \think\response\Json
    {
        $id = $this->request->param('id');
        if (!$id) {
            return $this->error(['message' => Constants::E_COMMON_INVALID_PARAM]);
        }
        $result = MenuModel::with('parent')->find($id)->toArray();
        if (!$result) {
            return $this->error(['message' => Constants::E_COMMON_RECORD_NOT_FOUND]);
        }
        if ($result['key']) {
            $result['translations'] = I18nModel::where('key', $result['key'])->column('value', 'lang_code');
        }
        return $this->success(['data' => $result]);
    }


    /**
     * 删除菜单数据
     * @return \think\response\Json
     */
    #[Auth('dev:menu:delete')]
    public function delete(): \think\response\Json
    {
        $ids = $this->request->post('id/a');
        if (empty($ids)) {
            return $this->error(['message' => Constants::E_COMMON_INVALID_PARAM]);
        }
        // 菜单是单选，返回的虽然是数组，但只有一个元素
        MenuService::deleteMenu($ids[0]);
        return $this->success();
    }


    /**
     *  拖拽排序
     * @return \think\response\Json
     */
    #[Auth('dev:menu:drag')]
    public function drag(): \think\response\Json
    {

        $fields = "newId,oldId,dragPos,orderBy,dragToChild";
        $data = $this->request->only(explode(',', $fields), 'post');
        SortableService::treeSort('dev_menu', $data);
        return $this->success();

    }


    /**
     * 修改任意字段
     * @return \think\response\Json
     */
    #[Auth('dev:menu:modify')]
    public function modify(): \think\response\Json
    {

        $post = $this->request->post();
        $keys = array_keys($post);
        $array = array_values(array_filter($keys, fn($v) => $v !== 'id'));
        $field = $array[0];
        if (!$post['id']) {
            return $this->error(['message' => Constants::E_COMMON_INVALID_PARAM]);
        }
        $model = MenuModel::find($post['id']);
        if (!$model) {
            return $this->error(['message' => Constants::E_COMMON_RECORD_NOT_FOUND]);
        }
        // 可以修改：状态、生成代码、是否可见、备注
        if (!in_array($field, ['status', 'gen_code', 'visible', 'remark'])) {
            return $this->error(['message' => Constants::E_COMMON_FORBIDDEN]);
        }

        $model[$field] = $post[$field];
        $result = $model->save();
        if (!$result) {
            throw new \Exception('更新状态失败');
        }
        return $this->success();

    }

    #[Auth('dev:menu:clean')]
    public function clean(): \think\response\Json
    {
        $confirm = $this->request->post('confirm', null);
        if (empty($confirm)) {
            $data = MenuService::cleanMenuConfirm();
        } else {
            $data = MenuService::cleanMenu();
        }
        return $this->success(['data' => $data]);
    }

    /**
     * 通过数据库表生成菜单
     * @return \think\response\Json
     */
    #[Auth('dev:menu:from_table')]
    public function fromTable(): \think\response\Json
    {
        $connect = $this->request->post('connect');
        $table = $this->request->post('table');
        $level = $this->request->post('level/d');
        Db::transaction(function () use ($connect, $table, $level) {
            // 检查补齐必要的字段信息到提供的数据库表
            $checkResult = DatabaseService::checkRepaireTable($table, $connect);
            if ($checkResult) {
                // 根据提交的信息生成新的菜单
                $menuData = DatabaseService::fromTableToMenuInfo($table, $connect, $level);
                $menuInfo = MenuModel::create($menuData);
                // 根据菜单、已存在的表的信息，生成字段信息
                $fieldDataList = DatabaseService::fromTableToFieldList($menuInfo['id']);
                foreach ($fieldDataList as $fieldData) {
                    FieldModel::create($fieldData);
                }
                // 为此菜单生成默认方法
                MenuService::addDefaultActions($menuInfo);
            } else {
                throw new \Exception('表结构不完善，请检查表结构');
            }
        });
        return $this->success();
    }


    /**
     * 生成代码
     * @return \think\response\Json
     */
    #[Auth('dev:menu:gen_code')]
    public function genCode()
    {
        // 菜单id
        $menu_id = $this->request->post('id/d');
        $overwrite = $this->request->post('overwrite/b');
        // 生成代码
        $data = MenuService::genCodeHandle($menu_id, $overwrite);
        // 返回结果
        return $this->success(['data' => $data]);
    }

    /**
     * 根据菜单id获得此菜单的权限前缀
     * @return \think\response\Json
     */
    public function getPermPrefix(): \think\response\Json
    {

        $menu_id = $this->request->post('menu_id', null, 'intval');
        $menu_info = MenuModel::find($menu_id);
        $menu_names = StrHelper::getMenuNames($menu_info['controller']);
        $prefix = $menu_names['code_prefix'];

        return $this->success(['data' => $prefix]);
    }


    /**
     * 拷贝菜单
     * @return \think\response\Json
     * @throws \Exception
     */
    #[Auth('dev:menu:copy')]
    public function copy(): \think\response\Json
    {
        $post = $this->request->post();
        MenuService::copyMenu($post);
        return $this->success();
    }


    //////////////////////////////公共接口//////////////////////////////////


    /**
     * 获取字典数据
     * @return \think\response\Json
     */
    public function getConnects(): \think\response\Json
    {
        // 数据库连接
        $connects = [];
        foreach (config('database.connections') as $k => $v) {
            $connects[] = ['label' => strtoupper($k), 'value' => $k];
        }
        return $this->success(['data' => $connects]);
    }

    public function getConnectTables(): \think\response\Json
    {
        $connect = $this->request->post('connect');
        $database = config('database.connections.' . $connect . '.database');
        $prefix = config('database.connections.' . $connect . '.prefix');
        $table_list = Db::connect($connect)->table('information_schema.tables')
            ->fieldRaw("TRIM(LEADING '{$prefix}' FROM table_name) as label, TRIM(LEADING '{$prefix}' FROM table_name) as value")
            ->where('table_schema', $database)
            ->whereRaw('table_name not like "' . $prefix . 'dev_%"')
            ->select();
        return $this->success(['data' => $table_list]);
    }


}
